package com.zrlh.file_trans_monitor.service;

import com.alibaba.fastjson.JSONObject;
import com.csvreader.CsvReader;
import com.csvreader.CsvWriter;
import com.zrlh.file_trans_monitor.entity.TaskConfEntity;
import com.zrlh.file_trans_monitor.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Service
@Slf4j
class FileMonitorServiceImpl implements FileMonitorService{
    @Value("${task.file.path}")
    private String taskFilePath;
    @Value("${monitor.message.endpoint}")
    private String endpoint;
    List<TaskConfEntity> taskConfEntityList=new ArrayList<>();
    List<TaskConfEntity> ERRORList=new ArrayList<>();
    Map<String,Boolean> resultMap=new HashMap<>();

    public synchronized void initTask() {
        taskConfEntityList.clear();
        log.info("FILE:"+taskFilePath);
        try {
            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(taskFilePath), StandardCharsets.UTF_8);
            CsvReader csvReader = new CsvReader(inputStreamReader);
            csvReader.readHeaders();
            while(csvReader.readRecord()){
                TaskConfEntity confInfo = new TaskConfEntity();
                confInfo.setTaskName(csvReader.get("任务名称"));
                confInfo.setExpectTime(Integer.valueOf(csvReader.get("期望时间")));
                confInfo.setLocalPath(csvReader.get("文件目录"));
                confInfo.setFileName(csvReader.get("文件名") == null?"":csvReader.get("文件名"));
                confInfo.setFileSuffix(csvReader.get("文件格式后缀"));
                confInfo.setFileNameType(Integer.valueOf(csvReader.get("文件命名格式")));
                taskConfEntityList.add(confInfo);
            }
            sortTaskList();
            log.info("GET FILE:"+taskConfEntityList.toString());
            setSTATUS();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ERROR from writing from CSV",e);
        }
    }
    public synchronized void writeCSV(){
        try {
            CsvWriter csvWriter=new CsvWriter(taskFilePath,',',StandardCharsets.UTF_8);
            String [] header = {"任务名称","期望时间","文件目录","文件名","文件格式后缀","文件命名格式"};
            csvWriter.writeRecord(header);
            String [] data=new String[7];
            for(TaskConfEntity confEntity:taskConfEntityList){
                data[0]=confEntity.getTaskName();
                data[1]=confEntity.getExpectTime().toString();
                data[2]=confEntity.getLocalPath();
                data[3]=confEntity.getFileName();
                data[4]=confEntity.getFileSuffix();
                data[5]=confEntity.getFileNameType().toString();
                csvWriter.writeRecord(data);
            }
            csvWriter.close();
            log.info("Have writed to CSV");
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ERROR from writing to CSV",e);

        }
    }

    public synchronized void cleanERRORList() {
        log.info("Task Error list at "+new Date()+" :\n"+ERRORList.toString());
        ERRORList.clear();
        resultMap.clear();//任务完成状态被清理
    }


    public void setSTATUS() {
        for(TaskConfEntity confEntity:taskConfEntityList){
            if(resultMap.get(confEntity.toString())!=null){
                confEntity.setStatus(true);
            }
            else
                confEntity.setStatus(false);
        }
    }


    public synchronized void sortTaskList() {
        Collections.sort(taskConfEntityList);
    }
    public synchronized void sortErrorList(){
        Collections.sort(ERRORList, new Comparator<TaskConfEntity>() {
            @Override
            public int compare(TaskConfEntity o1, TaskConfEntity o2) {
                return o2.getExpectTime()-o1.getExpectTime();
            }
        });
    }

    public List<TaskConfEntity> getTaskConfEntityList() {
        return taskConfEntityList;
    }

    public List<TaskConfEntity> getERRORList() {
        return ERRORList;
    }

    public String getPath(TaskConfEntity confEntity, String shortDate){
        String localPath;
        if(confEntity.getFileNameType() == 1) {
            localPath = confEntity.getLocalPath()+ File.separatorChar + confEntity.getFileName()+ shortDate.replace("-","")+confEntity.getFileSuffix();
        }else  if(confEntity.getFileNameType() == 2){
            localPath = confEntity.getLocalPath()+ File.separatorChar + confEntity.getFileName()+ shortDate+confEntity.getFileSuffix();
        }else{
            localPath = confEntity.getLocalPath()+ File.separatorChar + confEntity.getFileName()+ confEntity.getFileSuffix();
        }
        return localPath;
    }
    public boolean isExistFile(TaskConfEntity confEntity, String shortDate){
        boolean isExist;
        File file = new File(getPath(confEntity,shortDate));
        isExist=file.exists();
        if(confEntity.getFileNameType() == 3 && isExist){
            String lasttime=DateUtil.getDateString(new Date(file.lastModified()),"yyyy-MM-dd");
            if(lasttime.equals(shortDate))
            {
                isExist=true;
            }
            else
                isExist=false;
        }
        return isExist;
    }
    public synchronized String getMessage(){
        List<JSONObject> jsonObjectList=new ArrayList<>();
        Integer time = getCurrentHourMins();
        log.info("NOW(mmss):"+time);

        Iterator<TaskConfEntity> it = ERRORList.iterator();
        while(it.hasNext()){
            TaskConfEntity confEntity = it.next();
            boolean flag=false;
            flag=isExistFile(confEntity,DateUtil.getShortDateYYYY_MM_DDStrNow());
            JSONObject object = new JSONObject();
            object.put("metric","File.exist");
            object.put("endpoint",endpoint);
            object.put("timestamp",new Date().getTime());
            object.put("step",60);
            object.put("counterType","GAUGE");
            String tag= null;
            try {
                tag = "taskname="+confEntity.getTaskName()+",path="+confEntity.getLocalPath()+",filename="+confEntity.getFileName()+",localhost="+ InetAddress.getLocalHost();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            object.put("tags",tag);
            if(flag==true){
                object.put("value",1);
                resultMap.put(confEntity.toString(), true);
                it.remove();
            }
            else {
                object.put("value",0);
            }
            jsonObjectList.add(object);

        }
        for(TaskConfEntity confEntity:taskConfEntityList){
            boolean flag=false;
            if(!confEntity.isStatus()){
                if(confEntity.getExpectTime().equals(time) || confEntity.getExpectTime()<time){
                    flag=isExistFile(confEntity,DateUtil.getShortDateYYYY_MM_DDStrNow());
                    confEntity.setStatus(true);
                    JSONObject object = new JSONObject();
                    object.put("metric","File.exist");
                    object.put("endpoint",endpoint);
                    object.put("timestamp",new Date().getTime());
                    object.put("step",60);
                    object.put("counterType","GAUGE");
                    String tag= null;
                    try {
                        tag = "taskname="+confEntity.getTaskName()+",path="+confEntity.getLocalPath()+",filename="+confEntity.getFileName()+",localhost="+ InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    object.put("tags",tag);
                    if(flag==true){
                        object.put("value",1);
                        resultMap.put(confEntity.toString(), true);
                    }
                    else {
                        object.put("value",0);
                        resultMap.put(confEntity.toString(), false);
                        confEntity.setAbsolutePath(getPath(confEntity,DateUtil.getShortDateYYYY_MM_DDStrNow()));
                        ERRORList.add(confEntity);
                    }
                    jsonObjectList.add(object);
                }
            }
        }
        log.info("JSON to SEND: "+jsonObjectList.toString());
        return jsonObjectList.toString();
    }
    private static Integer getCurrentHourMins(){
        String nowWholeStr = DateUtil.getDateString(DateUtil.getCurrentTime(), DateUtil.YYYYMMDDHHDDSS);
        return Integer.valueOf(nowWholeStr.substring(8,12));
    }
    public void monitor(){
        Integer time = getCurrentHourMins();
        log.info("NOW(mmss):"+time);
        Iterator<TaskConfEntity> it = ERRORList.iterator();
        while(it.hasNext()){
            TaskConfEntity confEntity = it.next();
            boolean flag=false;
            flag=isExistFile(confEntity,DateUtil.getShortDateYYYY_MM_DDStrNow());
            log.info("Monitor:("+confEntity.toString()+","+flag+")");
            if(flag==true){
                resultMap.put(confEntity.toString(), true);
                it.remove();
            }
        }
        for(TaskConfEntity confEntity:taskConfEntityList){
            boolean flag=false;
            if(!confEntity.isStatus()){
                if(confEntity.getExpectTime().equals(time) || confEntity.getExpectTime()<time){
                    flag=isExistFile(confEntity,DateUtil.getShortDateYYYY_MM_DDStrNow());
                    log.info("Monitor:("+confEntity.toString()+","+flag+")");
                    confEntity.setStatus(true);
                    if(flag==true){
                        resultMap.put(confEntity.toString(), true);
                    }
                    else {
                        resultMap.put(confEntity.toString(), false);
                        confEntity.setAbsolutePath(getPath(confEntity,DateUtil.getShortDateYYYY_MM_DDStrNow()));
                        ERRORList.add(confEntity);
                    }
                }
            }
        }
    }

}
